package auth

import (
	"arc_srv4/common"
	"arc_srv4/logutils"
	"arc_srv4/middleware"
	"arc_srv4/utils"
	"github.com/dgrijalva/jwt-go"
	"github.com/kataras/iris/v12"
	"go.uber.org/zap"
	"strings"
	"time"
)

/**
 * 判断 token 是否有效
 * 如果有效 就获取信息并且保存到请求里面
 */
func CheckToken(ctx iris.Context) {
	// 普通验证模式 token 作为参数传入
	tk := new(common.TokenQuery)
	errs := ctx.ReadQuery(tk)
	if errs != nil && !iris.IsErrPath(errs) {
		ctx.StatusCode(iris.StatusInternalServerError)
		_, _ = ctx.JSON(common.ApiRspOnly{Code: common.Http10008, Message: common.Http10008Desc})
		return
	}

	paramToken := tk.Token
	var token *jwt.Token
	var err error
	if paramToken != "" {
		paramToken = strings.ReplaceAll(paramToken, "Bearer ", "")
		token, err = middleware.ParseToken(paramToken, []byte(common.JwtCfg.Secret)) //获取 access_token 信息
	} else {
		// jwt 验证模式 header中有 Authorization
		uu := ctx.Values().Get("jwt")
		if uu == nil {
			// 如果转化失败，则报没有token
			_, _ = ctx.JSON(common.ApiRspOnly{Code: common.Http10008, Message: common.Http10008Desc})
			return
		}

		u := uu.(*jwt.Token) //获取 token 信息
		paramToken = u.Raw
		token, err = middleware.ParseToken(paramToken, []byte(common.JwtCfg.Secret)) //获取 access_token 信息
	}

	if token == nil || err != nil {
		// 如果转化失败，则报没有token
		_, _ = ctx.JSON(common.ApiRspOnly{Code: common.Http10003, Message: common.Http10003Desc})
		return
	}

	if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {

		// 解析token中的信息
		var claimInfo = common.JwtClaimInfo{
			AppKey: claims["appKey"].(string),
			Expire: claims["expire"].(float64),
		}

		// token 过期
		logutils.Logger.Info("Expire", zap.Int64("Expire", int64(claimInfo.Expire)), zap.Int64("now", time.Now().Unix()))
		if int64(claimInfo.Expire) < time.Now().Unix() {
			_, _ = ctx.JSON(common.ApiRspOnly{Code: common.Http10004, Message: common.Http10004Desc})
			return
		}

		// 根据appKey取出redis中的token，并校验是否一致
		tokenRedis := string(utils.RedisGet(claimInfo.AppKey))
		if string(tokenRedis) == "" {
			_, _ = ctx.JSON(common.ApiRspOnly{Code: common.Http10004, Message: common.Http10004Desc})
			return
		}

		// 如果token不一致，则提示重新生成token
		if tokenRedis != paramToken {
			_, _ = ctx.JSON(common.ApiRspOnly{Code: common.Http10004, Message: common.Http10004Desc})
			return
		}
		// 写入head
		ctx.Values().Set("appKey", claimInfo.AppKey)

		// 判断调用次数
		ib := middleware.CheckApiTimes(claimInfo.AppKey, ctx.Path())
		if ib.IB != 200 {
			_, _ = ctx.JSON(common.ApiRspOnly{Code: ib.IB, Message: ib.Message})
			return
		}

		// 写入次数
		_ = middleware.InsertTimes(claimInfo.AppKey, ctx.Path())
		logutils.Logger.Info("insert times success", zap.String("appKey", claimInfo.AppKey))
		ctx.Next()

	} else {
		_, _ = ctx.JSON(common.ApiRspOnly{Code: common.Http10003, Message: common.Http10003Desc})
		ctx.Next()
	}

}
